package com.smart.redis.set;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.smart.redis.client.RedisClient;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;

/**
 * 
 * redis 中set的数据结构模型是
 * map<k,Set<?>>
 * 每个 set 可以存储40多亿个键值对（2的32次方减1） 
* @ClassName: Redis2Set 
* @Description: TODO redis set操作 (set中值唯一，不可重复)
* @Company:e-smart.top
* @author Thinkpad 
* @version 1.0 2018年8月30日 下午12:35:05
 */
public class Redis2Set {

	/**
	 * 
	* 假如 key 不存在，则创建一个只包含 value 元素作成员的集合
	* 当 key 不是集合类型时，报错
	* 
	* @Title: sadd 
	* @Description: TODO 向集合中添加数据（数据不可重复，否则操作不执行） 
	* @param @param key
	* @param @param values
	* @param @return    设定文件 
	* @return Long    返回类型 
	* @throws
	 */
	public static Long sadd(String key,String... values){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Long sadd = jedis.sadd(key, values);
			return sadd;
		} catch (Exception e) {
			// TODO: sadd 
			System.err.println("sadd : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	*
	* @Title: scard 
	* @Description: TODO 返回key对应集合中元素的数量
	* @param @param key
	* @param @return    设定文件 
	* @return Long    返回类型 
	* @throws
	 */
	public static Long scard(String key){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Long scard = jedis.scard(key);
			return scard;
		} catch (Exception e) {
			// TODO: scard 
			System.err.println("scard : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	* 不存在的 key 被视为空集
	* 
	* 这里的差集是第一个集合与其他集合都不同的元素集合
	* 
	* @Title: sdiff 
	* @Description: TODO 获取多个集合的差集（多个集合不一样的元素） 
	* @param @param keys
	* @param @return    设定文件 
	* @return Set<String>    返回类型 
	* @throws
	 */
	public static Set<String> sdiff(String... keys){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Set<String> sdiff = jedis.sdiff(keys);
			return sdiff;
		} catch (Exception e) {
			// TODO: sdiff 
			System.err.println("sdiff : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	* 如果 dstkey 集合已经存在，则将其覆盖
	* dstkey 可以是 key 本身
	*
	* @Title: sdiffstore 
	* @Description: TODO 获得多个集合的差集，并把差集集合保存到dstkey中
	* @param @param dstkey
	* @param @param keys
	* @param @return    设定文件 
	* @return Long    返回类型 
	* @throws
	 */
	public static Long sdiffstore(String dstkey,String... keys){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Long sdiffstore = jedis.sdiffstore(dstkey, keys);
			return sdiffstore;
		} catch (Exception e) {
			// TODO: sdiffstore 
			System.err.println("sdiffstore : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	* 不存在的 key 被视为空集
	* 当给定集合当中有一个空集时，结果也为空集(根据集合运算定律)
	* 
	* @Title: sinter 
	* @Description: TODO 获取多个集合的交集集合（多个集合都存在的元素集合） 
	* @param @param keys
	* @param @return    设定文件 
	* @return Set<String>    返回类型 
	* @throws
	 */
	public static Set<String> sinter(String... keys){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Set<String> sinter = jedis.sinter(keys);
			return sinter;
		} catch (Exception e) {
			// TODO: sinter 
			System.err.println("sinter : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	* 如果 dstkey 集合已经存在，则将其覆盖
	* dstkey 可以是 key 本身
	* 
	* 
	* @Title: sinterstore 
	* @Description: TODO  获取多个集合的交集集合（多个集合都存在的元素集合），便把集合保存的dstkey集合中
	* @param @param dstkey 
	* @param @param keys 
	* @param @return    设定文件 
	* @return Long    返回类型 
	* @throws
	 */
	public static Long sinterstore(String dstkey,String... keys){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Long sinterstore = jedis.sinterstore(dstkey, keys);
			return sinterstore;
		} catch (Exception e) {
			// TODO: sinterstore 
			System.err.println("sinterstore : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	*
	* @Title: sismember 
	* @Description: TODO 判断一个元素是不是存在于集合中 
	* @param @param key 键
	* @param @param value 元素
	* @param @return    设定文件 
	* @return Boolean    返回类型 
	* @throws
	 */
	public static Boolean sismember(String key,String value){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Boolean sismember = jedis.sismember(key, value);
			return sismember;
		} catch (Exception e) {
			// TODO: sismember 
			System.err.println("sismember : "+e.getMessage());
			return false;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	*
	* @Title: smembers 
	* @Description: TODO 获取集合中所有的元素 
	* @param @param key
	* @param @return    设定文件 
	* @return Set<String>    返回类型 
	* @throws
	 */
	public static Set<String> smembers(String key){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Set<String> smembers = jedis.smembers(key);
			return smembers;
		} catch (Exception e) {
			// TODO: smembers 
			System.err.println("smembers : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	* SMOVE 是原子性操作
	* 如果原集合中不存在元素，操作不执行
	* 如果目标集合中已经存在，操作的元素，则目标集合不变，单纯把操作元素从原集合中删除。
	* 如果两个键对应的数据类型不是set ，程序报错
	*
	* @Title: smove 
	* @Description: TODO 元素移动，从 srckey移动到dstkey集合中
	* @param @param srckey 元素原来所在集合的键
	* @param @param dstkey 元素要移动到的集合的键
	* @param @param value 元素
	* @param @return    设定文件 
	* @return Boolean    返回类型 
	* @throws
	 */
	public static Boolean smove(String srckey,String dstkey,String value){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Long smove = jedis.smove(srckey, dstkey, value);
			return smove==1l||smove==1;
		} catch (Exception e) {
			// TODO: smove 
			System.err.println("smove : "+e.getMessage());
			return false;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	* 当 key 不存在或 key 是空集时，返回 nil
	*
	* @Title: spop 
	* @Description: TODO 随机移除key集合中的一个元素，并返回 
	* @param @param key
	* @param @return    设定文件 
	* @return String    返回类型 
	* @throws
	 */
	public static String spop(String key){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			String spop = jedis.spop(key);
			return spop;
		} catch (Exception e) {
			// TODO: spop 
			System.err.println("spop : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	* 如果 count 为正数，且小于集合基数，那么命令返回一个包含 count 个元素的数组，数组中的元素各不相同
	* 如果 count 大于等于集合基数，那么返回整个集合
	* 如果 count 为负数，那么操作会返回一个元素列表，元素列表中的元素可能会重复出现多次，而元素列表的长度为 count 的绝对值
	* 
	* @Title: srandmember 
	* @Description: TODO 随机返回一定数量的集合元素 
	* @param @param key
	* @param @param count 返回数量表数（可正可负）
	* @param @return    设定文件 
	* @return List<String>    返回类型 
	* @throws
	 */
	public static List<String> srandmember(String key,int count){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			List<String> srandmember = jedis.srandmember(key, count);
			return srandmember;
		} catch (Exception e) {
			// TODO: srandmember 
			System.err.println("srandmember : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	*
	* @Title: srandmember 
	* @Description: TODO 随机返回集合中的一条元素
	* @param @param key
	* @param @return    设定文件 
	* @return String    返回类型 
	* @throws
	 */
	public static String srandmember(String key){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			String srandmember = jedis.srandmember(key);
			return srandmember;
		} catch (Exception e) {
			// TODO: srandmember 
			System.err.println("srandmember : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	* 不存在的 value 元素会被忽略
	* 当 key 不是集合类型，程序报错
	* @Title: srem 
	* @Description: TODO 删除key集合中的values数组中的元素
	* @param @param key
	* @param @param values 要删除的元素
	* @param @return    被删除的元素数量，不包含不存在的元素
	* @return Long    返回类型   
	* @throws
	 */
	public static Long srem(String key, String... values){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Long srem = jedis.srem(key, values);
			return srem;
		} catch (Exception e) {
			// TODO: srem 
			System.err.println("srem : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	* 如果多个集合中有重复元素，只保留一个元素。因为set中不能存在重复元素，重复元素会被合并成一个。
	*
	* @Title: sunion 
	* @Description: TODO 获取多个集合的并集（多个集合的所有元素集合） 
	* @param @param keys
	* @param @return    设定文件 
	* @return Set<String>    返回类型 
	* @throws
	 */
	public static Set<String> sunion(String... keys){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Set<String> sunion = jedis.sunion(keys);
			return sunion;
		} catch (Exception e) {
			// TODO: sunion 
			System.err.println("sunion : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	* 如果 dstkey 已经存在，则将其覆盖，没存在直接创建。
	* dstkey可以是keys中的一个
	*
	* @Title: sunionstore 
	* @Description: TODO  获取多个集合的并集（多个集合的所有元素集合），并保存到一个集合中
	* @param @param dstkey
	* @param @param keys
	* @param @return    设定文件 
	* @return Long    返回类型 
	* @throws
	 */
	public static Long sunionstore(String dstkey,String... keys){
		Jedis jedis = RedisClient.getJedis();
		try {
			
			Long sunionstore = jedis.sunionstore(dstkey,keys);
			return sunionstore;
		} catch (Exception e) {
			// TODO: sunionstore 
			System.err.println("sunionstore : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	/**
	 * 
	*
	* @Title: sscan 
	* @Description: TODO 查询key下所有匹配**value**的所有键值对集合
	* @param @param key
	* @param @param value 元素（**value**全匹配）
	* @param @return    设定文件 
	* @return List<String>    返回类型 
	* @throws
	 */
	public static List<String> sscan(String key,String value ){
		Jedis jedis = RedisClient.getJedis();
		try {
			String cursor = "0";
			List<String> values = new ArrayList<String>();
    		ScanParams sp = new ScanParams();
    		sp.match("*"+value+"*");//匹配规则pattern
    		sp.count(100);//每次查询数量
    		//迭代查询
    		do{
    			ScanResult<String> sscan = jedis.sscan(key, cursor, sp);
                List< String> result = sscan.getResult();
                if(result!=null && result.size() > 0){
                	values.addAll(result);
                }
                //再处理cursor
                cursor = sscan.getStringCursor();
            }while(!cursor.equals("0"));
    		
			return values;
		} catch (Exception e) {
			// TODO: sscan 
			System.err.println("sscan : "+e.getMessage());
			return null;
		} finally {
			RedisClient.returnToPool(jedis);
		}
	}
	public static void main(String[] args) {
//		sadd("set1", "1111","2222","11122","11333");
//		sadd("set2", "1111","3333","4444","11333");
		sadd("set3", "1111","3333","2222","sssss","4444");
		System.out.println(sdiff("set2","set1","set3").toString());
	}
}
